package devstar_devcontainer

import (
	"code.gitea.io/gitea/models/db"
	devstar_devcontainer_models "code.gitea.io/gitea/models/devstar_devcontainer"
	"code.gitea.io/gitea/modules/setting"
	"code.gitea.io/gitea/routers/api/devcontainer/vo"
	"context"
	"fmt"
	"xorm.io/builder"
)

// GetUserDevcontainersList 根据 userId 查询名下 devContainer 列表
func GetUserDevcontainersList(ctx context.Context, opts *vo.SearchUserDevcontainerListItemVoOptions) (vo.ListUserDevcontainersVO, error) {

	// 0. 构造异常返回时的空数据
	var resultDevContainerListVO = vo.ListUserDevcontainersVO{
		Page:          0,
		PageSize:      setting.UI.Admin.DevContainersPagingNum,
		PageTotalNum:  0,
		ItemTotalNum:  0,
		DevContainers: []vo.RepoDevContainerVO{},
	}

	// 1. 查询参数预处理
	if opts == nil || opts.Actor == nil {
		return resultDevContainerListVO, devstar_devcontainer_models.ErrFailedToOperateDevstarDevcontainerDB{
			Action:  "construct query condition for devContainer user list",
			Message: "invalid search condition",
		}
	}
	resultDevContainerListVO.UserID = opts.Actor.ID
	resultDevContainerListVO.Username = opts.Actor.Name
	if len(opts.OrderBy) == 0 {
		opts.OrderBy = "devcontainer_id DESC"
	}
	opts.PaginationOptions.ListAll = false // 强制使用分页查询，禁止一次性列举所有 devContainers
	if opts.PaginationOptions.Page <= 0 {  // 未指定页码/无效页码：查询第 1 页
		opts.PaginationOptions.Page = 1
	}
	if opts.PaginationOptions.PageSize <= 0 || opts.PaginationOptions.PageSize > setting.UI.Admin.DevContainersPagingNum {
		opts.PaginationOptions.PageSize = setting.UI.Admin.DevContainersPagingNum // /无效页面大小/超过每页最大限制：自动调整到系统最大开发容器页面大小
	}
	resultDevContainerListVO.Page = opts.PaginationOptions.Page
	resultDevContainerListVO.PageSize = opts.PaginationOptions.PageSize

	// 2. SQL 条件构建
	sqlCondition := builder.NewCond()
	sqlCondition = sqlCondition.And(builder.Eq{"user_id": opts.Actor.ID})

	// 3. 开启数据库事务，进行分页查询，同时封装 VO
	errDbTransaction := db.WithTx(ctx, func(ctx context.Context) error {
		var err error

		// 2.1 查询符合条件的记录总数
		/*
			SELECT COUNT(*)
			FROM devstar_devcontainer
			WHERE user_id = #{opts.Actor.ID}
		*/
		resultDevContainerListVO.ItemTotalNum, err = db.GetEngine(ctx).
			Table("devstar_devcontainer").
			Where(sqlCondition).
			Count()
		if err != nil {
			return devstar_devcontainer_models.ErrFailedToOperateDevstarDevcontainerDB{
				Action:  "count devContainer item numbers",
				Message: err.Error(),
			}
		}
		if resultDevContainerListVO.ItemTotalNum == 0 {
			return nil // 无符合记录，返回 nil 提交/结束 事务
		}

		// 2.2 计算分页参数
		totalRecords := resultDevContainerListVO.ItemTotalNum
		pageSize := int64(resultDevContainerListVO.PageSize)
		resultDevContainerListVO.PageTotalNum = int(totalRecords / pageSize)
		if totalRecords%pageSize > 0 {
			resultDevContainerListVO.PageTotalNum += 1
		}

		// 2.3 数据库带条件分页查询
		resultDevContainerListVO.DevContainers = make([]vo.RepoDevContainerVO, 0, opts.PaginationOptions.PageSize)
		/*
			SELECT
				devstar_devcontainer.id                                   AS devcontainer_id,
				devstar_devcontainer.name                                 AS devcontainer_name,
				devstar_devcontainer.devcontainer_host                    AS devcontainer_host,
				devstar_devcontainer.devcontainer_username                AS devcontainer_username,
				devstar_devcontainer.devcontainer_work_dir                AS devcontainer_work_dir,
				devstar_devcontainer.repo_id                              AS repo_id,
				repository.name                                           AS repo_name,
				repository.owner_name                                     AS repo_owner_name,
				repository.description                                    AS repo_description,
				CONCAT('/', repository.owner_name, '/', repository.name)  AS repo_link
			FROM devstar_devcontainer
			INNER JOIN repository ON devstar_devcontainer.repo_id = repository.id
			WHERE devstar_devcontainer.user_id = #{opts.Actor.ID}
			ORDER BY #{opts.OrderBy.String()}
			LIMIT    #{opts.PaginationOptions.PageSize}
			OFFSET   ( (#{opts.PaginationOptions.Page} - 1) * #{opts.PaginationOptions.PageSize});
		*/
		sess := db.GetEngine(ctx).
			Table("devstar_devcontainer").
			Select(""+
				"devstar_devcontainer.id                                   AS devcontainer_id,"+
				"devstar_devcontainer.name                                 AS devcontainer_name,"+
				"devstar_devcontainer.devcontainer_host                    AS devcontainer_host,"+
				"devstar_devcontainer.devcontainer_username                AS devcontainer_username,"+
				"devstar_devcontainer.devcontainer_work_dir                AS devcontainer_work_dir,"+
				"devstar_devcontainer.repo_id                              AS repo_id,"+
				"repository.name                                           AS repo_name,"+
				"repository.owner_name                                     AS repo_owner_name,"+
				"repository.description                                    AS repo_description,"+
				"CONCAT('/', repository.owner_name, '/', repository.name)  AS repo_link").
			Join("INNER", "repository", "devstar_devcontainer.repo_id = repository.id").
			Where(sqlCondition).
			OrderBy(opts.OrderBy.String())
		err = db.SetSessionPagination(sess, &opts.PaginationOptions).
			Find(&resultDevContainerListVO.DevContainers)
		if err != nil {
			// 查询出错，返回错误信息，结束事务
			return devstar_devcontainer_models.ErrFailedToOperateDevstarDevcontainerDB{
				Action:  fmt.Sprintf("list devContainer for user '%v' at page %v", opts.Actor.Name, opts.PaginationOptions.Page),
				Message: err.Error(),
			}
		}

		// 2.4 查询完成，返回 nil 自动提交事务
		return nil
	})

	if errDbTransaction != nil {
		return resultDevContainerListVO,
			devstar_devcontainer_models.ErrFailedToOperateDevstarDevcontainerDB{
				Action:  "query user DevContainer List",
				Message: errDbTransaction.Error(),
			}
	}

	return resultDevContainerListVO, nil
}
